package demo.javax.servlet.http;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import demo.java.lang.management.jvm.XdcsAddressUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ServletUtils {

    private static Logger logger = LoggerFactory.getLogger(ServletUtils.class);

    public static void printJsonWriter(Object content, HttpServletResponse response) {
        // 设置服务器端的编码,默认是ISO-8859-1；该方法必须在response.getWriter()之前进行设置
        response.setCharacterEncoding("UTF-8");
        // 通知浏览器服务器发送的数据格式
        response.setContentType("application/json;charset=utf-8");
        // response.setHeader("contentType", "text/html; charset=utf-8");
        try (PrintWriter writer = response.getWriter();) {
            writer.print(content);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * CSV文件列分隔符
     */
    private static final String CSV_COLUMN_SEPARATOR = ",";

    /**
     * CSV文件列分隔符
     */
    private static final String CSV_RN = "\r\n";

    /**
     * 获取value的字符串
     *
     * @param keys
     * @param map
     * @return
     */
    private static String parseValues(List<String> keys, Map<String, String> map) {
        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            String value = map.get(key);
            if (value == null) {
                sb.append("");
            } else {
                if (value.contains(",")) {
                    sb.append("\"").append(value).append("\"");
                } else {
                    sb.append(value);
                }
            }
            sb.append(",");
        }
        int length = sb.length();
        sb.deleteCharAt(length - 1);
        return sb.toString();
    }

    private ServletUtils() {
    }

    /**
     * 导出CSV
     *
     * @param response
     * @param head
     * @param body
     * @param fileName
     */
    public static void exportCsv(HttpServletResponse response, List<String> head, List<Map<String, String>> body,
                                 String fileName) throws IOException {
        // 设置响应
        response.setContentType("application/octet-stream");
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        // 以CSV方式导出的文件中默认不含BOM信息，通过给将要输出的内容设置BOM标识(以 EF BB BF 开头的字节流)即可解决该问题(文件中的中文乱码)。
        String bom = new String(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});
        response.setCharacterEncoding("UTF-8");
        try (ServletOutputStream servletOutputStream = response.getOutputStream();
             OutputStreamWriter printWriter = new OutputStreamWriter(servletOutputStream)) {
            printWriter.write(bom);
            if (head != null && head.size() > 0) {
                String headStr = head.stream().peek(e -> {
                    if (e.contains(",")) {
                        throw new IllegalArgumentException("非法字符‘,’");
                    }
                }).collect(Collectors.joining(","));
                printWriter.write(headStr);
                printWriter.write("\n");
            }
            if (body != null && !body.isEmpty()) {
                String bodys = body.stream()
                        .map(m -> parseValues(head, m))
                        .collect(Collectors.joining("\n"));
                printWriter.write(bodys);
            }
            printWriter.flush();
            response.flushBuffer();
        }

    }

    /**
     * 导出图片
     */
    public static void exportImage(HttpServletResponse response, String imgPath, String imageName) throws IOException {
        // 设置响应
        response.setContentType(MediaType.IMAGE_PNG_VALUE);
        response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(imageName, "UTF-8"));
        response.setStatus(200);
        try (ServletOutputStream servletOutputStream = response.getOutputStream()) {
            Path path = Paths.get(imgPath);
            byte[] bytes = Files.readAllBytes(path);
            servletOutputStream.write(bytes);
            response.flushBuffer();
        }
    }

    private static String CLIENT_REAL_IP = "X-REAL-IP";
    private static String CLIENT_REAL_PORT = "X-REAL-PORT";
    private static String X_CDN_SRC_IP = "X-CDN-SRC-IP";
    private static String X_F5_SRC_IP = "X-F5-SRC-IP";

    /**
     * 获取IP，能够获得经过代理之后的真实IP
     *
     * @param request
     * @return
     */
    public static String getRemoteAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        return ip;
    }

    public static String getClientRealIp(HttpServletRequest request) {
        // 获取经过cdn代理之前的真实ip
        String cdnSrcIp = request.getHeader(X_CDN_SRC_IP);
        if (cdnSrcIp != null && !cdnSrcIp.isEmpty()) {
            return cdnSrcIp;
        }

        // ipv6
        String ipv6 = request.getHeader(X_F5_SRC_IP);
        if (ipv6 != null && !ipv6.isEmpty()) {
            return ipv6;
        }

        String ip = request.getHeader(CLIENT_REAL_IP);
        if (ip == null || ip.isEmpty()) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    public static String getClientRealPort(HttpServletRequest request) {
        return request.getHeader(CLIENT_REAL_PORT);
    }

    public static void writeObjectResponseAsJson(HttpServletResponse response, Object object) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        try {
            out = response.getWriter();
            out.append(JSON.toJSONString(object));
        } catch (Exception e) {
            e.printStackTrace();
            response.sendError(500);
        }
    }


    /**
     * 导出文本
     *
     * @param fileName
     */
    public static ResponseEntity<InputStreamResource> exportFile(String filepath, String fileName) {
        try {
            File file = new File(filepath);

            fileName = URLEncoder.encode(fileName, "UTF-8");
            InputStream inputStream = Files.newInputStream(file.toPath());
            InputStreamResource resource = new InputStreamResource(inputStream);
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .contentLength(file.length())
                    .body(resource);
        } catch (Exception e) {
            logger.error("exportFile {}", filepath, e);
            return ResponseEntity
                    .status(500)
                    .body(null);
        }
    }

    /**
     * 导出文本
     *
     * @param fileName
     */
    public static ResponseEntity<String> buildResponseEntity(String filepath, String fileName) {
        try {
            String localIp = XdcsAddressUtil.getLocalIp();
            String localHost = XdcsAddressUtil.getLocalHost();
            JSONObject json = new JSONObject();
            json.put("文件路径", filepath);
            json.put("机器IP", localIp);
            json.put("机器名", localHost);
            json.put("状态", "异步执行中...");
            String data = json.toJSONString();
            return ResponseEntity.ok()
                    .contentType(MediaType.APPLICATION_JSON)
                    // 设置正确的内容长度:字符长度 vs 字节长度: contentLength 方法来准确描述字节数而不是字符数
                    .contentLength(data.getBytes(StandardCharsets.UTF_8).length)
                    .body(data);
        } catch (Exception e) {
            logger.error("exportFile {}", filepath, e);
            return ResponseEntity
                    .status(500)
                    .body(null);
        }
    }

}
